package com.dhms.vostok1.model

import android.util.Log
import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import com.dhms.basebusiness.R
import com.dhms.uikit.deviceCategory.DeviceCategoryItem
import com.dhms.uikit.deviceCategory.DeviceItem
import com.dhms.uikit.deviceCategory.DeviceSubCategoryItem

import com.dhms.vostok1.data.*
import com.dhms.vostok1.data.device_center.*
import com.dhms.vostok1.data.spot_patrol.CategoryDevices
import com.dhms.vostok1.data.spot_patrol.DeviceCategoryData
import com.dhms.vostok1.data.spot_patrol.ListDeviceItem
import com.dhms.vostok1.network.MoshiObject
import com.dhms.vostok1.service.net.NetworkApi
import com.dhms.vostok1.utils.secondTimeStamp
import com.dhms.vostok1.utils.toMap
import kotlinx.coroutines.launch
import java.util.*
import kotlin.collections.set

class DeviceViewModel : ViewModel() {

    private val _deviceListData = MutableLiveData<List<DeviceListItemData>>()
    val filteredDeviceListData: LiveData<List<DeviceListItemData>> = _deviceListData

    private val _currentDeviceData = MutableLiveData<DeviceListItemData?>()
    val currentDeviceData: LiveData<DeviceListItemData?> = _currentDeviceData

    private val _currentDeviceDetailData = MutableLiveData<DeviceDetailData?>(null)
    val currentDeviceDetailData: LiveData<DeviceDetailData?> = _currentDeviceDetailData

    private val _getDeviceListResult = MutableLiveData<ApiResult?>(null)
    val getDeviceListResult: LiveData<ApiResult?> = _getDeviceListResult

    var deviceListOffset: Int = 1

    private val _isDeviceListNoMore = MutableLiveData(false)
    val isDeviceListNoMore: LiveData<Boolean> = _isDeviceListNoMore

    private val _deviceFilters = MutableLiveData<MutableMap<String, Any?>>(mutableMapOf())
    val deviceFilters: LiveData<MutableMap<String, Any?>> = _deviceFilters

    private val _getDeviceMonitorInfoResult = MutableLiveData<ApiResult?>(null)
    val getDeviceMonitorInfoResult: LiveData<ApiResult?> = _getDeviceMonitorInfoResult

    private val _getDeviceDetailResult = MutableLiveData<ApiResult?>(null)
    val getDeviceDetailResult: LiveData<ApiResult?> = _getDeviceDetailResult

    private val _getDeviceStateStatisticDataResult = MutableLiveData<ApiResult?>(null)
    val getDeviceStateStatisticDataResult: LiveData<ApiResult?> = _getDeviceStateStatisticDataResult

    private val _devicePartsData = MutableLiveData<MutableMap<Long, DevicePartData>>(mutableMapOf())
    val devicePartsData: LiveData<MutableMap<Long, DevicePartData>> = _devicePartsData

    private val _currentDevicePartData = MutableLiveData<DevicePartData?>(null)
    val currentDevicePartData: LiveData<DevicePartData?> = _currentDevicePartData

    private val _currentMetricData = MutableLiveData<DeviceCollectionParamItem?>(null)
    val currentMetricData: LiveData<DeviceCollectionParamItem?> = _currentMetricData

    private val _deviceStateStatisticData = MutableLiveData<DeviceStateStatisticData?>(null)
    val deviceStateStatisticData: LiveData<DeviceStateStatisticData?> = _deviceStateStatisticData

    var currentCategoryID: Int = -1

    //是否搜索状态
    private var searchState: Boolean = false

    //搜索的名字
    private var searchName: String? = null

    //筛选前的分类数据源
    var categoryList: List<DeviceCategoryItem>? = null

    //所有原始分类数据
    private var _allCategoryList: List<DeviceCategoryData>? = null

    //所有的分类设备
    private var _allCategoryDevices: MutableMap<Int, CategoryDevices> = mutableMapOf()

    private val _deviceCategoryData = MutableLiveData<List<DeviceCategoryItem>?>(null)
    val deviceCategoryData: LiveData<List<DeviceCategoryItem>?> = _deviceCategoryData

    private val _deviceSubData = MutableLiveData<List<DeviceSubCategoryItem>?>(null)
    val deviceSubData: LiveData<List<DeviceSubCategoryItem>?> = _deviceSubData

    private val _topLevelCategory = MutableLiveData<List<TopLevelCategoryData>?>(null)
    val topLevelCategory: LiveData<List<TopLevelCategoryData>?> = _topLevelCategory

    private val _deviceParamChartsTimeRange = MutableLiveData(defaultTimeRange)
    val deviceParamChartsTimeRange: LiveData<MutableList<Date>> = _deviceParamChartsTimeRange

    var devicePointItems: List<DevicePointData>? = null

    fun getDeviceListData() {
        if (getDeviceListResult.value?.state == ApiState.LOADING) {
            return
        }

        _getDeviceListResult.value = ApiResult(ApiState.LOADING)
        viewModelScope.launch {
            val queryMap = DeviceListQueryData(
                deShowStatus = deviceFilters.value?.get("deShowStatus") as String?,
                deCategoryCuId = deviceFilters.value?.get("deCategoryCuId") as Int?,
                deName = deviceFilters.value?.get("deName") as String?,
                offset = deviceListOffset
            )
            if (deviceFilters.value?.get("deShowStatus") != null) {
                queryMap.deHasSensor = "yes"
            }
            val res = NetworkApi.getDeviceList(queryMap.toMap()!!)
            Log.d(TAG, "The res to get device list is: $res with query $queryMap.")

            val error = res.exceptionOrNull()
            if (error != null) {
                _getDeviceListResult.value = ApiResult(ApiState.ERROR, error.message ?: "获取失败！")
                Log.e(TAG, "error: $error")

                return@launch
            }

            _getDeviceListResult.value = ApiResult(ApiState.DONE)
            val listData = res.getOrNull()?.body()?.data?.data ?: listOf()
            _deviceListData.value = listOf(
                *(filteredDeviceListData.value?.toTypedArray() ?: arrayOf()),
                *listData.toTypedArray()
            )
            if (listData.size < DEFAULT_PAGE_LIMIT) {
                _isDeviceListNoMore.value = true
            }
            deviceListOffset += 1
        }
    }

    fun getDeviceByDeviceId(deviceId: Long?, complete: ((item: DeviceListItemData?) -> Unit)) {
        viewModelScope.launch {
            val queryMap = DeviceListQueryData(
                deId = deviceId
            )

            val res = NetworkApi.getDeviceList(queryMap.toMap()!!)
            Log.d(TAG, "The res to get device list is: $res with query $queryMap.")

            val error = res.exceptionOrNull()
            if (error != null) {
                Log.e(TAG, "error: $error")
                complete(null)
                return@launch
            }

            val listData = res.getOrNull()?.body()?.data?.data ?: listOf()
            if (listData.isNotEmpty()) {
                complete(listData[0])
            } else {
                complete(null)
            }
        }
    }


    fun setDeviceListFilters(filters: Map<String, Any?>) {
        initDeviceListLoadState()
        _deviceListData.value = listOf()
        val oldFilters = deviceFilters.value?.toMutableMap() ?: mutableMapOf()
        oldFilters.putAll(filters)
        _deviceFilters.value = oldFilters
    }

    private fun initDeviceListLoadState() {
        deviceListOffset = 1
        _isDeviceListNoMore.value = false
    }

    fun getDeviceCategory() {
        viewModelScope.launch {
            val categoryRes = NetworkApi.getDeviceCategory()
            val list = categoryRes.getOrNull()?.body()?.data
            _allCategoryList = list
            val b = list?.filter { it.isRootNode }?.map { DeviceCategoryItem(it.ctID, it.ctName) }
            categoryList = b
            _deviceCategoryData.value = b
        }
    }

    fun getTopLevelCategory() {
        viewModelScope.launch {
            val categoryRes = NetworkApi.getTopLevelCategory()
            val list = categoryRes.getOrNull()?.body()?.data?.sortedBy { it.ct_id }
            _topLevelCategory.value = list
        }
    }

    fun getAllCategoryDevices() {
        viewModelScope.launch {
            val res = NetworkApi.getCategoryDevices()
            val list = res.getOrNull()?.body()?.data
            _allCategoryDevices = mutableMapOf()
            //不同公司下会有重复的分类，所以要把洗下数据，把不同公司的分类归并到一起
            list?.forEach {
                it.categoryDevices?.forEach { category ->
                    val catID = category.id
                    val items = category.devices
                    if (items != null && items.isNotEmpty()) {

                        if (_allCategoryDevices.containsKey(catID)) {
                            //已经存在的category
                            var c = _allCategoryDevices[catID]

                            var mutableDevices: MutableList<ListDeviceItem> =
                                c?.devices?.toMutableList() ?: mutableListOf()
                            items.forEach { item ->
                                val deID = item.id
                                if (mutableDevices.firstOrNull { item.id == deID } == null) {
                                    mutableDevices.add(item)
                                }
                            }
                            c?.devices = mutableDevices

                        } else {
                            _allCategoryDevices[catID] = category
                        }

                    }
                }
            }

        }
    }

    fun getDeviceItems(categoryID: Int) {
        currentCategoryID = categoryID
        val subCategories = mutableListOf<DeviceSubCategoryItem>()

        //获取这个一级分类下的所有分类设备
        //筛选这个目录下的所有分类[包含root结点]
        val categories =
            _allCategoryList?.filter { !it.isRootNode && it.rootNode == categoryID }


        var rootItems = _allCategoryDevices[categoryID]?.devices
        if (searchState && searchName != null) {
            rootItems = rootItems?.filter { it.name.contains(searchName!!) }
        }

        if (rootItems != null && rootItems.isNotEmpty()) {
            val items = rootItems.map { DeviceItem(it.id, it.name, categoryID) }
            subCategories.add(DeviceSubCategoryItem(categoryID, null, categoryID, items))
        }

        categories?.forEach {
            val cid = it.ctID
            val cname = it.ctName
            var catItems = _allCategoryDevices[cid]?.devices
            if (searchState && searchName != null) {
                catItems = catItems?.filter { it.name.contains(searchName!!) }
            }
            if (catItems != null && catItems.isNotEmpty()) {
                val items = catItems.map { DeviceItem(it.id, it.name, cid) }
                subCategories.add(DeviceSubCategoryItem(cid, cname, categoryID, items))
            }
        }

        //println("getDeviceItems: $categoryID, source: $subCategorys")
        _deviceSubData.value = subCategories
    }

    fun getFilterData(name: String?) {
        searchName = name
        if (name == null || name.isEmpty()) {
            searchState = false
            _deviceCategoryData.value = categoryList
            return
        }
        searchState = true
        val matchCategories = mutableListOf<Int>()
        _allCategoryDevices.forEach { category ->
            val m = category.value.devices?.firstOrNull { it.name.contains(name) }
            if (m != null) {
                matchCategories.add(category.key)
            }
        }

        //根结点
        val rootIds = mutableListOf<Int>()
        matchCategories.forEach { catId ->
            //根据 catId 找到 他的 root
            _allCategoryList?.firstOrNull { it.ctID == catId }?.rootNode?.let { id ->
                if (!rootIds.contains(id)) {
                    rootIds.add(id)
                }
            }
        }

        val items = mutableListOf<DeviceCategoryItem>()
        rootIds.forEach { rootId ->
            val m = categoryList?.firstOrNull { item ->
                item.ct_id == rootId
            }

            if (m != null) {
                items.add(m)
            }
        }

        _deviceCategoryData.value = items
    }

    fun setCurrentDevice(deviceData: DeviceListItemData?) {
        _currentDeviceData.value = deviceData
    }

    fun setDeviceCategoryData(deviceCategory: List<DeviceCategoryItem>?) {
        _deviceCategoryData.value = deviceCategory
    }

    fun setDeviceSubData(deviceSubCategory: List<DeviceSubCategoryItem>?) {
        _deviceSubData.value = deviceSubCategory
    }

    fun getDeviceMonitorInfoData() {
        if (getDeviceMonitorInfoResult.value?.state == ApiState.LOADING) {
            return
        }
        _getDeviceMonitorInfoResult.value = ApiResult(ApiState.LOADING)

        getDamageStatisticDevice {

            viewModelScope.launch {
                val monitorInfoQuery = DeviceDynamicMonitorQueryData(
                    currentDeviceData.value!!.deId.toString(),
                    "real",
                    action = "param",
                    fakePart = "true"
                )
                val res = NetworkApi.getDeviceDynamicMonitorInfo(monitorInfoQuery.toMap()!!)
                Log.d(TAG, "The res to get device monitor info is: $res.")

                val error = res.exceptionOrNull()
                if (error != null) {
                    _getDeviceListResult.value = ApiResult(ApiState.ERROR, error.message ?: "获取失败！")
                    Log.e(TAG, "error: $error")

                    return@launch
                }

                val collectionPoints = res.getOrNull()?.body()?.data?.collectionPoints
                val collectionParams = res.getOrNull()?.body()?.data?.collectionParams
                val partsData = mutableMapOf<Long, DevicePartData>()

                var devicePartInfo: Map<String, Any?>? = null
                try {
                    devicePartInfo =
                        if (currentDeviceData.value?.deTreeChartConfig != null) currentDeviceData.value!!.deTreeChartConfig?.let {
                            MoshiObject.jsonAdapter.fromJson(
                                it
                            )
                        } else null
                } catch (e: Exception) {
                    Log.e(TAG, e.message.toString())
                }

                if (devicePartInfo != null) {
                    val collectPointsDrawingData = getDeviceCollectPointsDrawingData(
                        devicePartInfo,
                        collectionPoints?.map { it.cpId })
                    collectionPoints?.forEach {
                        partsData[it.cpId] = DevicePartData(
                            it.cpId,
                            it.cpName,
                            mutableListOf(),
                            point = collectPointsDrawingData.drawingData[it.cpId],
                            size = collectPointsDrawingData.size
                        )
                    }
                }

                val cpList = partsData.keys
                val metricTagOrderMap = mutableMapOf<Long, Int>()
                cpList.forEach {
                    metricTagOrderMap[it] = 99999
                }
                collectionParams?.forEach {
                    if (cpList.indexOf(it.collectionPointId) != -1) {
                        val tags = it.paramTags.split(",")
                        var metricTag: String? = null

                        tags.forEach { tag ->
                            val order = PARAM_ORDER.indexOf(tag)
                            if (order != -1 && order < metricTagOrderMap[it.collectionPointId]!!) {
                                metricTagOrderMap[it.collectionPointId] = order
                                metricTag = tag
                            }
                        }

                        partsData[it.collectionPointId]?.collectionParams?.add(it)

                        val lastMetricTagOrder = PARAM_ORDER.indexOf(
                            partsData[it.collectionPointId]!!.currentMetricTag
                        )

                        if (partsData[it.collectionPointId]?.currentMetricNo == null) {
                            partsData[it.collectionPointId]?.apply {
                                currentMetricNo = it.metricNo
                                currentMetricName = it.paramName
                                currentMetricUnit = it.unitName
                                currentMetricTag = metricTag
                            }
                        } else if ((metricTagOrderMap[it.collectionPointId] != 99999 && metricTagOrderMap[it.collectionPointId]!! < lastMetricTagOrder) || lastMetricTagOrder == -1) {
                            partsData[it.collectionPointId]?.apply {
                                currentMetricNo = it.metricNo
                                currentMetricName = it.paramName
                                currentMetricUnit = it.unitName
                                currentMetricTag = metricTag
                            }
                        }
                    }
                }
                partsData.keys.forEach {
                    val partData = partsData[it] ?: return@forEach
                    val partDataCurrentMetricNo = partData.currentMetricNo ?: return@forEach
                    partData.currentMetricData = getMetricTSDBData(partDataCurrentMetricNo)
                }
                _devicePartsData.value = partsData

                _getDeviceMonitorInfoResult.value = ApiResult(ApiState.DONE)
            }
        }

    }

    private fun getDamageStatisticDevice(complete: () -> Unit) {
        viewModelScope.launch {
            val deviceId = currentDeviceData.value!!.deId
            val res = NetworkApi.getDamageStatisticDevice(deviceId)
            val error = res.exceptionOrNull()
            if (error != null) {
                Log.e(TAG, "getDamageStatisticDevice error: $error")
                complete()
            }

            res.getOrNull()?.body()?.data?.items?.let {
                devicePointItems = it
            }

            complete()
        }
    }

    fun updateCurrentMetricData(
        cpId: Long,
        metricNo: String,
        metricName: String,
        metricUnit: String? = null,
    ) {
        viewModelScope.launch {
            val partsData: MutableMap<Long, DevicePartData> = mutableMapOf()
            partsData.putAll(devicePartsData.value!!)
            partsData[cpId]?.currentMetricNo = metricNo
            partsData[cpId]?.currentMetricName = metricName
            partsData[cpId]?.currentMetricUnit = metricUnit
            partsData[cpId]?.currentMetricData = getMetricTSDBData(metricNo)
            _devicePartsData.value = partsData
        }
    }

    fun clearDevicePartsData() {
        _devicePartsData.value = mutableMapOf()
        _getDeviceMonitorInfoResult.value = null
    }

    fun getDeviceDetail() {
        if (getDeviceDetailResult.value?.state == ApiState.LOADING) {
            return
        }
        val deviceId = currentDeviceData.value?.deId
        if (deviceId == null) {
            _getDeviceDetailResult.value = ApiResult(
                ApiState.ERROR,
                "设备信息为空！"
            )
        }
        viewModelScope.launch {
            val res = NetworkApi.getDeviceDetail(deviceId!!)
            Log.d(TAG, "The res to get device detail is: $res.")

            val error = res.exceptionOrNull()
            if (error != null) {
                _getDeviceListResult.value = ApiResult(ApiState.ERROR, error.message ?: "获取失败！")
                Log.e(TAG, "error: $error")

                return@launch
            }

            val data = res.getOrNull()?.body()?.data
            _currentDeviceDetailData.value = data
            _getDeviceDetailResult.value = ApiResult(ApiState.DONE)
        }
    }

    private suspend fun getMetricTSDBData(
        metric: String,
        timeRange: MutableList<Long> = mutableListOf()
    ): Map<String, TSDBResSourcesData> {
        if (timeRange.isEmpty()) {
            val currentTime = Date().secondTimeStamp()
            timeRange.add(0, currentTime - 86400)
            timeRange.add(1, currentTime)
        }
        val body = TSDBReqBody(
            timeRange[0],
            timeRange[1],
            listOf(
                TSDBDeviceReqItem(
                    downsample = "20s-max",
                    filters = listOf(
                        TSDBDeviceFilter(
                            "${currentDeviceData.value!!.deId}",
                            "deviceid",
                            "literal_or"
                        )
                    ),
                    metric = metric,
                )
            )
        )
        val res = NetworkApi.getTSDBData(body)
        Log.d(TAG, "The res to get device tsdb data is: $res with body: $body.")

        val error = res.exceptionOrNull()
        if (error != null) {
            Log.e(TAG, "error: $error")

            return mapOf()
        }

        return res.getOrNull()?.body()?.data?.get(0)?.sources ?: mapOf()
    }

    fun setCurrentDevicePartData(data: DevicePartData) {
        _currentDevicePartData.value = data
    }

    fun getCPMetricData(timeRange: List<Long> = mutableListOf(), metricIndex: Int? = null) {
        val partData = currentDevicePartData.value?.copy() ?: return
        viewModelScope.launch {
            if (metricIndex != null) {
                partData.collectionParams[metricIndex].metricData = getMetricTSDBData(
                    partData.collectionParams[metricIndex].metricNo,
                    timeRange.toMutableList()
                )
            } else {
                val paramCount = partData.collectionParams.size
                val firstLoadCount = if (paramCount > 3) 3 else paramCount
                val collectionParams =
                    partData.collectionParams.take(firstLoadCount).map {
                        it.metricData = getMetricTSDBData(
                            it.metricNo,
                            timeRange.toMutableList()
                        )
                        it
                    }
                collectionParams.forEachIndexed { index, item ->
                    partData.collectionParams[index] = item
                }
            }
            _currentDevicePartData.value = partData
        }
    }

    fun clearCPMetricData() {
        val partData = currentDevicePartData.value?.copy() ?: return
        for (index in 0 until partData.collectionParams.size) {
            partData.collectionParams[index].metricData = null
        }
        _currentDevicePartData.value = partData
    }

    fun setCurrentMetricData(metricData: DeviceCollectionParamItem) {
        _currentMetricData.value = metricData
    }

    fun getDeviceStateStatisticData() {
        _getDeviceStateStatisticDataResult.value = ApiResult(ApiState.LOADING)
        viewModelScope.launch {
            val res = NetworkApi.getDeviceStateStatisticData()
            Log.d(TAG, "The res to get device state statistic data is: $res.")

            val error = res.exceptionOrNull()
            if (error != null) {
                _deviceStateStatisticData.value = null
                _getDeviceStateStatisticDataResult.value =
                    ApiResult(ApiState.ERROR, error.message ?: "获取失败！")
                Log.e(TAG, "error: $error")

                return@launch
            }

            val resData = res.getOrNull()?.body()?.data

            val hasSensorState = resData?.hasSensorState ?: listOf()
            //val noSensorState = resData?.noSensorState ?: listOf()

            var runningDeviceCount = 0
            var stopDeviceCount = 0
            var offlineDeviceCount = 0

            hasSensorState.forEach {
                when (it?.deviceState) {
                    DEVICE_STATE_RUNNING -> runningDeviceCount += it.count
                    DEVICE_STATE_STOP -> stopDeviceCount += it.count
                    DEVICE_STATE_UNKNOWN -> offlineDeviceCount += it.count
                }
            }
            // 只统计在线监测设备
            //noSensorState.forEach {
            //    when (it?.deviceState) {
            //        DEVICE_STATE_RUNNING -> runningDeviceCount += it.count
            //        DEVICE_STATE_STOP -> stopDeviceCount += it.count
            //        DEVICE_STATE_UNKNOWN -> offlineDeviceCount += it.count
            //    }
            //}

            _deviceStateStatisticData.value = mapOf(
                DEVICE_STATE_RUNNING to runningDeviceCount,
                DEVICE_STATE_STOP to stopDeviceCount,
                DEVICE_STATE_UNKNOWN to offlineDeviceCount,
            )
            _getDeviceStateStatisticDataResult.value = ApiResult(ApiState.DONE)
        }
    }

    fun setParamChartsTimeRange(timeRange: MutableList<Date>) {
        _deviceParamChartsTimeRange.value = timeRange
    }

    companion object {
        const val TAG = "DeviceViewModel"

        val defaultTimeRange
            get() = run {
                val calendar = Calendar.getInstance()
                calendar.add(Calendar.DATE, -1)
                mutableListOf(calendar.time, Date())
            }

        const val DEVICE_STATE_RUNNING = 2 // 'running' // 运行
        const val DEVICE_STATE_STOP = 1 // 'downtime' // 停机
        const val DEVICE_STATE_UNKNOWN = 0 // 'unknown' // 未知

        const val DEVICE_STATE_OFFLINE_TEXT = "离线"
        const val DEVICE_STATE_RUNNING_TEXT = "运行"
        const val DEVICE_STATE_STOP_TEXT = "停机"

        val DEFAULT_DEVICE_LIST_QUERY = DeviceListQueryData(
            offset = DEFAULT_PAGE_OFFSET,
            showDeviceChart = "true"
        )

        val DEVICE_STATE_MAP = mapOf(
            DEVICE_STATE_RUNNING to mapOf(
                "name" to DEVICE_STATE_RUNNING_TEXT,
                "color" to R.color.status_normal
            ),
            DEVICE_STATE_STOP to mapOf(
                "name" to DEVICE_STATE_STOP_TEXT,
                "color" to R.color.status_abnormal
            ),
            DEVICE_STATE_UNKNOWN to mapOf(
                "name" to DEVICE_STATE_OFFLINE_TEXT,
                "color" to R.color.status_unknown
            ),
        )

        val DEVICE_LIST_STATE_MAP = mapOf(
            DEVICE_STATE_RUNNING to mapOf(
                "name" to DEVICE_STATE_RUNNING_TEXT,
                "color" to R.color.device_state_run_color
            ),
            DEVICE_STATE_STOP to mapOf(
                "name" to DEVICE_STATE_STOP_TEXT,
                "color" to R.color.device_state_stop_color
            ),
            DEVICE_STATE_UNKNOWN to mapOf(
                "name" to DEVICE_STATE_OFFLINE_TEXT,
                "color" to R.color.device_state_offline_color
            ),
        )

        // 参数类型
        const val PARAM_USE_TYPE_NORMAL = 1
        const val PARAM_USE_TYPE_IGNORE = 2 // 客户可以忽略参数
        const val PARAM_USE_TYPE_PROFESSIONAL = 5 // 设备专业参数

        //测点,设备
        private val NODE_TYPE_LIST = listOf<String>("device", "cp")

        // 参数顺序
        val PARAM_ORDER = listOf(
            "vib-hw-a2v",
            "vib-rvel",
            "vib-anlysis-peak",
            "vib-pacc",
            "TMPR-anlysis",
            "tmpr-anlysis"
        )

        @Suppress("UNCHECKED_CAST")
        fun getDeviceCollectPointsDrawingData(
            devicePartInfo: Map<String, Any?>,
            collectPointIdList: List<Long>?
        ): DeviceCollectPointsDrawingData {
            val cpMap = devicePartInfo["cp_node_id_map"] as Map<String, String>?
            val nodeInfoMap =
                devicePartInfo["node_info_map"] as Map<String, Map<String, Any?>>?
//            val cpIcon = devicePartInfo["cpIcon"] as String?

            /**
             * 可以通过下列方法计算出图片宽度以及图片起始坐标，但其实接口已经生成图片了，只需计算出图片与原始"画布"的间距，从而算出真实坐标就好了
             */
            var maxX: Double? = null
            var maxY: Double? = null
            var minX: Double? = null
            var minY: Double? = null
            nodeInfoMap?.values?.forEach {
                if (!NODE_TYPE_LIST.contains(it["node_type"])) {
                    return@forEach
                }

                var partMaxX = 0.0
                var partMaxY = 0.0
                var partMinX = 0.0
                var partMinY = 0.0
                try {
                    partMaxX = it["x"] as Double + it["width"] as Double
                    partMaxY = it["y"] as Double + it["height"] as Double
                    partMinX = it["x"] as Double
                    partMinY = it["y"] as Double
                } catch (ex: Exception) {
                    // data error
                    partMaxX = 0.0
                    partMaxY = 0.0
                    partMinX = 0.0
                    partMinY = 0.0
                }
                if (maxX == null || partMaxX >= maxX!!) maxX = partMaxX
                if (maxY == null || partMaxY >= maxY!!) maxY = partMaxY
                if (minX == null || partMinX <= minX!!) minX = partMinX
                if (minY == null || partMinY <= minY!!) minY = partMinY
            }
            val realWidth = if (maxX != null && minX != null) maxX!! - minX!! else null
            val realHeight = if (maxY != null && maxY != null) maxY!! - minY!! else null

//            val realWidth = maxX
//            val realHeight = maxY

            val collectPointDrawingData = mutableMapOf<Long, List<Double>?>()
            collectPointIdList?.forEach {
                val nodeInfo = nodeInfoMap?.get(cpMap?.get(it.toString()))
                val x = nodeInfo?.get("x") as Double?
                val y = nodeInfo?.get("y") as Double?
                val point = if (x != null && y != null && minX != null && minY != null) listOf(
                    x - minX!!,
                    y - minY!!
                ) else null

                collectPointDrawingData[it] = point
            }

            return DeviceCollectPointsDrawingData(
                if (realWidth != null && realHeight != null) listOf(
                    realWidth,
                    realHeight
                ) else null,
                collectPointDrawingData
            )
        }
    }
}